package cn.hpclub.server.controller.admin;


import cn.hpclub.server.bean.SerialObject;
import cn.hpclub.server.model.TransactionLog;
import cn.hpclub.server.service.ApiLogService;
import cn.hpclub.server.util.ExcelRenderUtil;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class ApiLogController extends BaseAdminController<TransactionLog> {
    private static final Logger logger = LoggerFactory.getLogger(ApiLogController.class);
    private static final SimpleDateFormat sdfMinute = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    private static final SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");

    private void initSelectApi() {
        List<Record> list = Db.find("select api from api_describe");
        setAttr("api_options", list);
    }

    /**
     * 接口某个时间段内的调用情况列表
     */
    public void apiTimeRangeTable() {
        ConcurrentHashMap<String, String> searchInfo = getSearchInfo();
        Calendar calendar = Calendar.getInstance();
        String time_end = sdfMinute.format(calendar.getTime());
        if (searchInfo.containsKey("time_end")) {
            time_end = searchInfo.get("time_end");
        }
        calendar.add(Calendar.MINUTE, -1);//默认当前时间和前一分钟
        String time_start = sdfMinute.format(calendar.getTime());
        if (searchInfo.containsKey("time_start")) {
            time_start = searchInfo.get("time_start");
        }
        String api = "sPubOpenUser";
        if (searchInfo.containsKey("api")) {
            if (!"-1".equals(searchInfo.get("api"))) {
                api = searchInfo.get("api");
            }
        }
        logger.info(time_start + ":" + time_end + ":" + api);
        initSelectApi();
        setAttr("time_start", time_start);
        setAttr("time_end", time_end);
        setAttr("api", api);

        Record record = ApiLogService.service.queryTimeRange(api, time_start, time_end);
        String apiResult = record.getStr("api");
        if (StrKit.isBlank(apiResult)) {//这一段时间统计数据为零的情况加上接口名
            record.set("api", api);
        }
        setAttr("record", record);
        render("/admin/api_time_range_table.tpl");
    }

    /**
     * 接口按天的调用情况列表
     */
    public void apiTimeRangeByDayTable() {
        ConcurrentHashMap<String, String> searchInfo = getSearchInfo();
        Calendar calendar = Calendar.getInstance();
        String time_end = sdfDay.format(calendar.getTime());
        if (searchInfo.containsKey("time_end")) {
            time_end = searchInfo.get("time_end");
        }
        calendar.add(Calendar.DAY_OF_MONTH, -1);//默认当前时间和前一天
        String time_start = sdfDay.format(calendar.getTime());
        if (searchInfo.containsKey("time_start")) {
            time_start = searchInfo.get("time_start");
        }
        String api = "sPubOpenUser";
        if (searchInfo.containsKey("api")) {
            if (!"-1".equals(searchInfo.get("api"))) {
                api = searchInfo.get("api");
            }

        }
        logger.info(time_start + ":" + time_end + ":" + api);
        initSelectApi();
        setAttr("time_start", time_start);
        setAttr("time_end", time_end);
        setAttr("api", api);

        List<Record> records = ApiLogService.service.queryTimeRangeByDay(api, time_start, time_end);
        setAttr("records", records);
        render("/admin/api_time_range_table_byday.tpl");
    }

    /**
     * 接口按天的调用情况导出
     */
    public void apiTimeRangeByDayExport() {
        ConcurrentHashMap<String, String> searchInfo = getSearchInfo();
        Calendar calendar = Calendar.getInstance();
        String time_end = sdfDay.format(calendar.getTime());
        if (searchInfo.containsKey("time_end")) {
            time_end = searchInfo.get("time_end");
        }
        calendar.add(Calendar.DAY_OF_MONTH, -1);//默认当前时间和前一天
        String time_start = sdfDay.format(calendar.getTime());
        if (searchInfo.containsKey("time_start")) {
            time_start = searchInfo.get("time_start");
        }
        String api = "sPubOpenUser";
        if (searchInfo.containsKey("api")) {
            if (!"-1".equals(searchInfo.get("api"))) {
                api = searchInfo.get("api");
            }

        }
        logger.info(time_start + ":" + time_end + ":" + api);
        initSelectApi();
        setAttr("time_start", time_start);
        setAttr("time_end", time_end);
        setAttr("api", api);
        SXSSFWorkbook workbook = ApiLogService.service.getExcel(api, time_start, time_end);
        render(new ExcelRenderUtil(workbook, api + " 按天调用统计"));
    }

    /**
     * 接口某个时间段内的图表展示
     */
    public void apiTimeRangeCharts() {
        ConcurrentHashMap<String, String> searchInfo = getSearchInfo();
        Calendar calendar = Calendar.getInstance();
        String time_end = sdfMinute.format(calendar.getTime());
        if (searchInfo.containsKey("time_end")) {
            time_end = searchInfo.get("time_end");
        }
        calendar.add(Calendar.MINUTE, -1);//默认当前时间和前一分钟
        String time_start = sdfMinute.format(calendar.getTime());
        if (searchInfo.containsKey("time_start")) {
            time_start = searchInfo.get("time_start");
        }
        String api = "sPubOpenUser";
        if (searchInfo.containsKey("api")) {
            if (!"-1".equals(searchInfo.get("api"))) {
                api = searchInfo.get("api");
            }

        }
        logger.info(time_start + ":" + time_end + ":" + api);
        setAttr("time_start", time_start);
        setAttr("time_end", time_end);
        setAttr("api", api);
        initSelectApi();
        render("/admin/api_time_range_charts.tpl");
    }

    public void getChartsData() {
        String api = getPara("api", "sPubOpenUser");
        Calendar calendar = Calendar.getInstance();
        String time_end = getPara("time_end", sdfMinute.format(calendar.getTime()));
        calendar.add(Calendar.MINUTE, -1);//默认当前时间和前一分钟
        String time_start = getPara("time_start", sdfMinute.format(calendar.getTime()));
        logger.info(time_start + ":" + time_end + ":" + api);

        List<Record> records = ApiLogService.service.getChartsData(api, time_start, time_end);
        List<List<Long>> totalSerial = new ArrayList<List<Long>>();
        List<List<Long>> apiFailedSerial = new ArrayList<List<Long>>();
        List<List<Long>> businessFailedSerial = new ArrayList<List<Long>>();

        long totalAll = 0;
        long apiFailedAll = 0;
        long businessFailedAll = 0;
        long less1000All = 0;
        long in10005000All = 0;//1-3 3-5
        long in500010000All = 0;
        long in1000015000All = 0;
        long more15000All = 0;
        for (Record record : records) {
            /*String opt_time = record.getStr("opt_time");
            long time = 0;
            try {
                time = sdfMinute.parse(opt_time).getTime();
            } catch (Exception e) {
                e.printStackTrace();
            }*/
            long time = record.getLong("opt_time");
            long total = record.getLong("total");
            long apiFailed = record.getLong("apiFailed");
            long businessFailed = record.getLong("businessFailed");

            List<Long> totalArr = arrCompose(time, total);
            totalSerial.add(totalArr);
            List<Long> apiFailedArr = arrCompose(time, apiFailed);
            apiFailedSerial.add(apiFailedArr);
            List<Long> businessFailedArr = arrCompose(time, businessFailed);
            businessFailedSerial.add(businessFailedArr);

            totalAll += total;
            apiFailedAll += apiFailed;
            businessFailedAll += businessFailed;
            less1000All += record.getLong("less1000");
            in10005000All += record.getLong("in10003000") + record.getLong("in30005000");
            in500010000All += record.getLong("in500010000");
            in1000015000All += record.getLong("in1000015000");
            more15000All += record.getLong("more15000");
        }
        SerialObject totalObject = new SerialObject("调用量", totalSerial);
        SerialObject apiFailedObject = new SerialObject("接口失败量", apiFailedSerial);
        SerialObject businessFailedObject = new SerialObject("业务失败量", businessFailedSerial);

        List<SerialObject> chartData = new ArrayList<SerialObject>(3);
        chartData.add(totalObject);
        chartData.add(apiFailedObject);
        chartData.add(businessFailedObject);

        long totalAllNot0 = (totalAll == 0) ? 1 : totalAll;//防止为0
        JSONObject caculate = new JSONObject().put("totalAll", totalAll).put("apiFailedAll", apiFailedAll).put("businessFailedAll", businessFailedAll)
                .put("businessFailedAllPercent", " (" + ApiLogService.dfPercent.format(100.0 * businessFailedAll / totalAllNot0) + "%)").put("apiFailedAllPercent", " (" + ApiLogService.dfPercent.format(100.0 * apiFailedAll / totalAllNot0) + "%)")
                .put("less1000All", less1000All + " (" + ApiLogService.dfPercent.format(100.0 * less1000All / totalAllNot0) + "%)").put("in10005000All", in10005000All + " (" + ApiLogService.dfPercent.format(100.0 * in10005000All / totalAllNot0) + "%)")
                .put("in500010000All", in500010000All + " (" + ApiLogService.dfPercent.format(100.0 * in500010000All / totalAllNot0) + "%)").put("in1000015000All", in1000015000All + " (" + ApiLogService.dfPercent.format(100.0 * in1000015000All / totalAllNot0) + "%)")
                .put("more15000All", more15000All + " (" + ApiLogService.dfPercent.format(100.0 * more15000All / totalAllNot0) + "%)");
        JSONObject all = new JSONObject().put("data", caculate).put("chart", chartData);
        renderJson(all.toString());
    }

    /**
     * @param opt_time 毫秒数
     * @param total
     * @return
     */
    private List<Long> arrCompose(long opt_time, long total) {
        List<Long> totalArr = new ArrayList<Long>(2);
        totalArr.add(opt_time);
        totalArr.add(total);
        return totalArr;
    }

    /**
     * 一定时间范围内根据返回码统计
     */
    public void codeCount() {
        ConcurrentHashMap<String, String> searchInfo = getSearchInfo();
        Calendar calendar = Calendar.getInstance();
        String time_end = sdfMinute.format(calendar.getTime());
        if (searchInfo.containsKey("time_end")) {
            time_end = searchInfo.get("time_end");
        }
        calendar.add(Calendar.MINUTE, -1);//默认当前时间和前一分钟
        String time_start = sdfMinute.format(calendar.getTime());
        if (searchInfo.containsKey("time_start")) {
            time_start = searchInfo.get("time_start");
        }
        String api = "sPubOpenUser";
        if (searchInfo.containsKey("api")) {
            if (!"-1".equals(searchInfo.get("api"))) {
                api = searchInfo.get("api");
            }

        }
        logger.info(time_start + ":" + time_end + ":" + api);
        initSelectApi();
        setAttr("time_start", time_start);
        setAttr("time_end", time_end);
        setAttr("api", api);

        List<Record> records = ApiLogService.service.codeCount(api, time_start, time_end);
        setAttr("records", records);
        render("/admin/api_time_range_code.tpl");
    }
}
